<template>
	<editor
		:id="`${id}textarea`"
		:inline="true"
		@onInit="handleInit"
		:value="parsedValue"
		:init="config"
		ref="zcoInput"
		:style="{ pointerEvents: showDetail ? 'none' : 'auto', minHeight: autosize.minRows * 36 + 'px', maxHeight: autosize.maxRows * 36 + 'px' }"
		class="tinymce-textarea"
		@keydown.native="handleKeydown"
		@keyup.native="handleKeydown"
	/>
</template>

<script>
const ZCO_TAG = `<span class="mceNonEditable el-tag el-tag--info el-tag--light">ZCO_TAG_TEXT1<span class="mce-hide">ZCO_TAG_TEXT2</span>}}</span>`;
const ZCO_TAG_2 = `<span class="mceNonEditable el-tag el-tag--info el-tag--light">ZCO_TAG_TEXT1</span>`;
const ZCO_BEGIN_TAG = `&#xFEFF;`; // '\u00A0' `\n`

import { mapState, mapActions } from 'vuex';
// import tinymce from "tinymce"; // tinymce.min.js
import Editor from '@tinymce/tinymce-vue';
// We're manually importing theme, icons and plugins because otherwise TinyMCE tries to resolve
// them himself and load throught http, but this won't work with chrome extension
// Theme
// import "tinymce/themes/silver/theme.min.js";
// import "tinymce/models/dom/model.js";
// import "tinymce/icons/default/icons.js";
// /* Import content css */
// /* Import content css */
import { contentUiCss } from '../tinycss/ui/oxide/content.js';
import { contentCss } from '../tinycss/content/default/content.js';
const config = {
	height: '200',
	min_height: 200,
	menubar: false,
	plugins: [], // wordcount
	// ax_wordlimit_num:40,
    // ax_wordlimit_callback: function(editor,txt,num){
    //     console.log('当前字数：' + txt.length + '，限制字数：' + num);
    // },
	toolbar: false,
	inline: true,
	noneditable_class: 'mceNonEditable',
	skin: false,
	content_css: false,
	newline_behavior: '',
	// content_style: contentUiCss.toString() + "\n" + contentCss.toString(),
	force_root_block: '',
	paste_block_drop: true
};

window.tinymce = tinymce;

const ax_wordlimit = function(editor) {
    var pluginName='字数限制';
    var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
    var global$2 = tinymce.util.Tools.resolve('tinymce.util.Delay');
    var ax_wordlimit_type = editor.getParam('ax_wordlimit_type', 'letter' );
    var ax_wordlimit_num = editor.getParam('ax_wordlimit_num', false );
    var ax_wordlimit_delay = editor.getParam('ax_wordlimit_delay', 500 );
    var ax_wordlimit_callback = editor.getParam('ax_wordlimit_callback', function(){} );
    var ax_wordlimit_event = editor.getParam('ax_wordlimit_event', 'SetContent Undo Redo Keyup' );
    var onsign=1;
    //统计方法1：计算总字符数
    var sumLetter = function(){
        var html = editor.getContent();
        var re1 = new RegExp("<.+?>","g");
        var txt = html.replace(re1,'');
        txt = txt.replace(/\n/g,'');
        txt = txt.replace(/&nbsp;/g,' ');
        var num=txt.length;
        return {txt:txt,num:num}
    }
    var onAct = function(){
        if(onsign){
            onsign=0;
            //此处预留更多统计方法
            switch(ax_wordlimit_type){
                case 'letter':
                default:
                    var res = sumLetter();
            }
            if( res.num > ax_wordlimit_num ){
                ax_wordlimit_callback(editor, res.txt, ax_wordlimit_num);
            }
            setTimeout(function(){onsign=1}, ax_wordlimit_delay);
        }
        
    }
    var setup = function(){
        if( ax_wordlimit_num > 0 ){
            global$2.setEditorTimeout(editor, function(){
                var doth = editor.on(ax_wordlimit_event, onAct);
            }, 300);
        }
    };

    setup();

    return {
        getMetadata: function () {
            return  {
                name: pluginName,
                url: "http://tinymce.ax-z.cn/more-plugins/ax_wordlimit.php",
            };
        }
    };
};

// tinymce.PluginManager.add('ax_wordlimit', ax_wordlimit);

export default {
	components: { Editor },
	props: {
		value: {
			type: String,
			default: () => ''
		},
		id: {
			type: String,
			default: () => 'myTiny'
		},
		required: {
			type: Boolean,
			default: () => false
		},
		minlength: {
			type: Number,
			default: () => 1
		},
		maxlength: {
			type: Number,
			default: () => 0
		},
		useWordLimit: {
			type: Boolean,
			default: () => false
		},
		showDetail: {
			type: Boolean,
			default: () => false
		},
		placeholder: {
			type: String,
			default: () => ''
		},
		autosize: {
			type: Object,
			default: () => ({ minRows: 1, maxRows: 3 })
		}
	},
	watch: {
		insert(newVal) {
			const { id, variable } = newVal || {};
			if (id === this.$refs.zcoInput.id) {
				this.insertKeyword(variable);
			}
		},
		value(newVal) {
			if (!this.editor) return;
			if (newVal) {
				if (this.editor.getContent({ format: 'text' }) !== newVal) {
					this.editor.setContent('');
					this.parse(newVal);
				}
			} else {
				this.editor.setContent('');
			}
		}
	},

	computed: {
		...mapState({
			insert: state => state.variable.insert
		})
	},

	data() {
		return {
			editor: null,
			config: {
				...config,
				placeholder: this.placeholder,
				max_chars: this.maxlength,
				content_style: contentUiCss + '\n' + contentCss
			},
			completeContent: '',
			parsedValue: '',
			disabled: false
		};
	},

	mounted() {
		this.$nextTick(() => {
			this.parse(this.value);
			this.disabled = true;
		});
		console.log('config', this.config);
	},
	beforeDestroy() {},

	methods: {
		...mapActions('variable', ['setInsertVariable']),

		findNextEditableNode(node, next) {
			let currentNode = next ? node.nextSibling : node.previousSibling; // nextSibling
			while (currentNode) {
				if (currentNode.nodeType === 3 && currentNode.tagName !== 'SPAN') {
					return currentNode;
				}
				currentNode = next ? currentNode.nextSibling : currentNode.previousSibling;
			}

			return null;
		},

		handleKeydown(e) {
			if (e.keyCode === 13) {
				e.preventDefault();
				e.stopPropagation();
				e.stopImmediatePropagation();
				return false;
			}
			var allowedKeys = [8, 16, 17, 18, 20, 33, 34, 35, 36, 38, 40, 46];
			if (allowedKeys.indexOf(e.keyCode) != -1) return true;
			if (e.ctrlKey) return true;

			if ([37, 39].includes(e.keyCode) && this.editor.selection.getNode().tagName === 'SPAN') {
				// 左箭头按键的键码
				e.preventDefault(); // 阻止默认行为
				e.stopPropagation();
				e.stopImmediatePropagation();
				// 找到下一个可编辑的节点
				const next = e.keyCode === 39;
				const nextEditableNode = this.findNextEditableNode(this.editor.selection.getNode(), next);

				if (nextEditableNode) {
					this.editor.selection.setCursorLocation(nextEditableNode, next ? 0 : nextEditableNode.textContent.length);
					return false;
				} else if (next) {
					const node = this.editor.selection.getNode().parentNode;
					this.editor.selection.setCursorLocation(node, node.childNodes.length);
					this.editor.execCommand('mceInsertContent', false, ZCO_BEGIN_TAG);
					this.$nextTick(() => {
						this.editor.selection.setCursorLocation(node, node.childNodes.length);
					});
					return false;
				} else {
					const node = this.editor.selection.getNode();
					this.editor.selection.setCursorLocation(node.parentNode, 0);
					this.editor.execCommand('mceInsertContent', false, ZCO_BEGIN_TAG);
					return false;
				}
			}
		},

		handleInit(evt, editor) {
			// 一些控制键
			var allowedKeys = [8, 16, 17, 18, 20, 33, 34, 35, 36, 37, 38, 39, 40, 46, 91, 93];
			this.editor = editor;
			let isChinese = false;
			let resetContent = () => {
				isChinese = true;
				let content = editor.getContent({ format: 'text' });
				editor.setContent('');
				this.parse(content.length < this.maxlength ? content : this.completeContent);
				isChinese = false;
				this.$refs.zcoInput.$el.scrollTo(0, 100000);

			};
			this.$nextTick(() => {
				this.parse(this.value);
			});
			editor.on('change input', e => {
				if (!isChinese){
					this.handleUpdate(editor.getContent({ format: 'text' }));
				}
			});
			editor.on('compositionstart', function (e) {
				isChinese = true
			});
			editor.on('compositionend', function (e) {
				isChinese = false
			});
			editor.on('keydown KeyUp Undo Redo', e => {
				// 13: Enter, 38: Up Arrow, 40: Down Arrow
				if ([13, 38, 40].includes(e.keyCode)) {
					e.preventDefault();
					e.stopPropagation();
					return false;
				}
				// 匹配到一些控制键返回 true，如：退格键等
				if (allowedKeys.indexOf(e.keyCode) != -1) return true;
				if (this.maxlength && !isChinese) {
					const content = editor.getContent({ format: 'text' });
					const wordSize = content ? content.length : 0;
					if ( wordSize > this.maxlength){
						if (!this.completeContent || this.completeContent.length < this.maxlength){
							this.completeContent = content.substring(0, this.maxlength);
						}
						resetContent();
					} else if (wordSize < this.maxlength){
						this.completeContent = content;
					} else {
						if (this.completeContent?.length < this.maxlength){
							this.completeContent = content;
						}
						// 当达到最大输入长度时，稍微延迟一下再修复内容，否则会导致复制快捷键失效
						setTimeout(() => {
							resetContent();
						}, 100);
					}
				}
				if (!isChinese){
					this.handleUpdate(editor.getContent({ format: 'text' }));
				}
				return true;
			});
			editor.on('paste', e => {
				setTimeout(() => {
					resetContent();
					this.handleUpdate(editor.getContent({ format: 'text' }));
				}, 100);
			});
		},

		handleUpdate(value) {
			value = this.editor.getContent({ format: 'text' });
			// value - value.replace(/(<|&lt;)br\s*\/*(>|&gt;)/g, '');
			if (!value) {
				this.$emit('input', value);
				this.completeContent = value;
				return;
			}
			const length = value.length;
			if (this.maxlength && length <= this.maxlength) {
				if (length <= this.maxlength){
					this.$emit('input', value);
					this.completeContent = value;
				} else {
					this.$emit('input', value.substring(0, this.maxlength));
					this.completeContent = value.substring(0, this.maxlength);
				}
			} else {
				this.$emit('input', value);
				this.completeContent = value;
			}
		},

		parse(str) {
			if (!str) {
				return;
			}
			const pattern = /({{[^{}]+}})|([^{}]+)/g;
			str.match(pattern).map(match => {
				if (match.startsWith('{{') && match.endsWith('}}')) {
					this.insertKeyword(match);
				} else {
					this.insertText(match);
				}
			});
		},

		insertText(insertText) {
			// console.log('insertText：', insertText);
			if (insertText && this.editor) {
				const length = this.editor.getContent({ format: 'text' }).length;
				if (this.maxlength && length + insertText.length > this.maxlength) {
					insertText = insertText.substring(0, this.maxlength - length);
				}
				this.editor.execCommand('mceInsertContent', false, insertText);
			}
		},

		insertKeyword(insertText) {
			// console.log('insertKeyword：', insertText);
			if (insertText && this.editor) {
				const length = this.editor.getContent({ format: 'text' }).length;
				if (this.maxlength && length + insertText.length > this.maxlength) {
					return;
				}
				let tag = this.formatTag(insertText);
				this.editor.execCommand('mceInsertContent', false, tag);
			}
		},

		formatTag(text) {
			let tag = ZCO_TAG;
			let subs = text.split('_');
			if (subs.length > 1) {
				const text2 = '_' + subs[subs.length - 1].split('}')[0];
				subs.splice(subs.length - 1, 1);
				let text1 = subs.join('_');
				tag = tag.replace(/ZCO_TAG_TEXT1/g, text1);
				tag = tag.replace(/ZCO_TAG_TEXT2/g, text2);
			} else {
				tag = ZCO_TAG_2.replace(/ZCO_TAG_TEXT1/g, text);
			}

			return tag;
		}
	}
};
</script>

<style lang="less">
.mce-hide {
	/* visibility: hidden; */
	width: 0;
	max-width: 0;
	height: 0;
	max-height: 0;
	display: inline-flex;
	color: #00000000;
	width: 0;
	max-width: 0;
	height: 0;
	max-height: 0;
	display: inline-flex;
	white-space: nowrap;
	flex-wrap: nowrap;
	overflow: hidden;
}
.tinymce-textarea {
	border: 1px solid #dcdfe6;
	border-radius: 4px;
	padding: 0 15px;
	height: fit-content;
	outline: none;
	overflow-y: auto;
	background: #ffffff;
	word-break: break-all;
	line-height: 26px;
	box-sizing: border-box;
	font-size: 14px;
	width: calc(100% - 54px);

	p {
		margin: 0;
		padding: 0;
	}

	.el-tag.el-tag--info {
		margin: 0 2px 9px 2px;
	}
}
.tinymce-textarea:not([dir='rtl'])[data-mce-placeholder]:not(.mce-visualblocks)::before {
	left: 15px !important;
	line-height: 34px;
	color: #c0c4cc;
}
.mce-content-body[data-mce-placeholder].mce-edit-focus::before {
	content: '' !important;
}
.tinymce-textarea:focus {
	border-color: #409eff !important;
	outline: none;
}
.mceNonEditable {
	pointer-events: none;
}
</style>
